<?php

namespace App\Kuafu\ProductMenu\Service;

use App\Exceptions\BaseException;
use App\Kuafu\Base\Enum\ClientEnum;
use App\Kuafu\Base\Enum\DBEnum;
use App\Kuafu\Category\Model\CategoryModel;
use App\Kuafu\Category\Service\CategoryService;
use App\Kuafu\Common\Service\CommonService;
use App\Kuafu\Mqtt\Service\MqttQueueService;
use App\Kuafu\Product\Enum\CodeEnum;
use App\Kuafu\Product\Enum\ProductCacheEnum;
use App\Kuafu\Product\Enum\ProductCodeEnum;
use App\Kuafu\Product\Exceptions\ProductException;
use App\Kuafu\Product\Model\PackageProductMapping;
use App\Kuafu\Product\Model\Product;
use App\Kuafu\Product\Service\PackageProductService;
use App\Kuafu\Product\Service\ProductService;
use App\Kuafu\Product\Service\ProductShopService;
use App\Kuafu\ProductMenu\Exceptions\ProductMenuException;
use App\Kuafu\ProductMenu\Enum\ProductMenuCodeEnum;
use App\Kuafu\ProductMenu\Model\ProductMenu;
use App\Kuafu\Shop\Enum\ShopCacheEnum;
use App\Kuafu\Shop\Enum\ShopCodeEnum;
use App\Kuafu\Shop\Exceptions\ShopException;
use App\Kuafu\Shop\Model\Shop;
use App\Kuafu\Shop\Model\ShopProductStatus;
use App\Kuafu\Shop\Service\ShopService;
use App\Kuafu\User\Service\AuthService;
use Carbon\Carbon;
use Illuminate\Support\Facades\Cache;
use App\Kuafu\Base\Service\BaseService;
use Illuminate\Support\Facades\DB;

class ProductMenuService extends BaseService
{
    public static function getMenu(
        int $productMenuId,
        string $name,
        int $pageSize,
        int $pageNum,
        array $ids,
        string $sortField,
        string $sortType
    ): array {
        $query = ProductMenu::getDataPage($productMenuId, $name, $pageSize, $pageNum, $ids, $sortField, $sortType);

        // 添加使用菜单的店铺数量
        $lists = collect($query->items())->map(function ($item) {
            $item                    = $item->toArray();
            $item['shopNum']         = $item['bind_shop_rel_count'];
            $item['createdByUidRel'] = $item['created_by_uid_rel'];
            $item['updatedByUidRel'] = $item['updated_by_uid_rel'];
            $item['createdAt']       = date('Y-m-d H:i:s', strtotime($item['createdAt']));
            $item['updatedAt']       = date('Y-m-d H:i:s', strtotime($item['updatedAt']));

            unset($item['bind_shop_rel_count'], $item['created_by_uid_rel'], $item['updated_by_uid_rel'], $item['createdByUid'], $item['updatedByUid'], $item['isDeleted']);
            return $item;
        });

        return [
            'pageNum'   => $query->currentPage(),
            'pageSize'  => $query->perPage(),
            'pageCount' => ceil($query->total() / $query->perPage()),
            'count'     => $query->total(),
            'lists'     => $lists,
        ];
    }

    public static function addMenu(
        int $brandId,
        string $name,
        string $desc,
        array $productList,
        array $categoryList
    ): void {
        if (ProductMenu::checkName($brandId, $name)) {
            throw new ProductMenuException(ProductMenuCodeEnum::ERR_FOOD_MENUS_NAME_EXISTS);
        }

        if (!Product::checkProductIds($brandId, array_column($productList, 'productId'))) {
            throw new ProductException(ProductCodeEnum::ERR_PRODUCT_NOT_EXIST);
        }

        // 临时方案，判断是新增还是复制
        $fCategoryId = $categoryList[0]['categoryId'];
        $fPid        = CategoryModel::query()->where('id', $fCategoryId)->value('pid');
        if ($fPid == 0) {

            // 新增
            $operateType = 'add';
        } else {

            // 复制
            $operateType = 'copy';
        }

        DB::beginTransaction();
        try {
            // productMenu表新增
            $menu = ProductMenu::addData($brandId, $name, $desc);

            if ($operateType == 'add') {

                // category表新增
                CategoryService::batchAddCategory($brandId, $menu['id'], $categoryList);
            } else {

                // category复制
                CategoryService::batchCopyCategory($brandId, $menu['id'], $categoryList);
            }

            // products表新增
            ProductService::batchAddProducts($menu['id'], $productList);
            // packageProductMapping修改
            PackageProductService::batchAddPackAgeProduct($productList, $menu['id']);
            DB::commit();
        } catch (\Exception $exception) {
            DB::rollBack();
            throw new ProductMenuException(ProductMenuCodeEnum::ERR_FOOD_MENUS_DB_SET, '', $exception);
        }

    }

    /**
     * 设置菜单&绑定菜品信息
     *
     * 根据底层菜品，自动更新菜品镜像信息
     * 若底层菜品被删除，则自动删除镜像中的内容
     * @param int $brandId
     * @param int $productMenuId
     * @param string $name
     * @param string $desc
     * @param array $productList
     * @param array $categoryList
     * @throws ProductException
     * @throws ProductMenuException
     * @throws \App\Kuafu\User\Exceptions\UserException
     */
    public static function setMenu(
        int $brandId,
        int $productMenuId,
        string $name,
        string $desc,
        array $productList,
        array $categoryList
    ): void {
        $menu = ProductMenu::checkId($brandId, $productMenuId);
        if (!$menu) {
            throw new ProductMenuException(ProductMenuCodeEnum::ERR_FOOD_MENUS_ID);
        }

        if (ProductMenu::checkName($brandId, $name, $productMenuId)) {
            throw new ProductMenuException(ProductMenuCodeEnum::ERR_FOOD_MENUS_NAME_EXISTS);
        }

        if (!Product::checkProductIdsGetIds($brandId, array_column($productList, 'productId'))) {
            throw new ProductException(ProductCodeEnum::ERR_PRODUCT_NOT_EXIST);
        }

        $user         = AuthService::getAuthUser();
        $updatedByUid = $user['id'];

        if (!ProductMenu::setData($productMenuId, $name, $desc, $updatedByUid)) {
            throw new ProductMenuException(ProductMenuCodeEnum::ERR_FOOD_MENUS_DB_SET);
        }
        DB::beginTransaction();
        // category表编辑
        CategoryService::batchEditCategory($brandId, $productMenuId, $categoryList);
        // products表编辑
        ProductService::batchEditProducts($brandId, $productMenuId, $productList);
        //packageProduct表编辑
        PackageProductService::batchEditPackageProduct($productList, $productMenuId);
        DB::commit();

        Cache::forget(ProductCacheEnum::getProductList($productMenuId));

        // 更新菜单对应门店
        $shopList = Shop::query()->where('menuId', $productMenuId)->get()->pluck('id')->toArray();

        MqttQueueService::updateProductMenu($shopList);
    }

    public static function setMenuStatus(int $productMenuId, int $status): void
    {
        $query = ProductMenu::query()->find($productMenuId);
        if (!$query) {
            throw new ProductMenuException(ProductMenuCodeEnum::ERR_FOOD_MENUS_ID);
        }

        $user      = AuthService::getAuthUser();
        $updatedBy = $user['username'];

        if (!ProductMenu::setStatus($productMenuId, $status, $updatedBy)) {
            throw new ProductMenuException(ProductMenuCodeEnum::ERR_FOOD_MENUS_DB_ONLINE);
        }
    }

    public static function delMenu(int $brandId, int $productMenuId): void
    {
        $menu = ProductMenu::checkId($brandId, $productMenuId);
        if (!$menu) {
            throw new ProductMenuException(ProductMenuCodeEnum::ERR_FOOD_MENUS_ID);
        }

        // 检查是否有店铺使用
        $shopNum = Shop::countShopsByMenuId($productMenuId);
        if ($shopNum) {
            throw new ProductMenuException(ProductMenuCodeEnum::ERR_FOOD_MENUS_SHOP_USING);
        }

        $user         = AuthService::getAuthUser();
        $updatedByUid = $user['id'];

        if (!ProductMenu::delData($productMenuId, $updatedByUid)) {
            throw new ProductMenuException(ProductMenuCodeEnum::ERR_FOOD_MENUS_DB_DEL);
        }
    }

    /**
     * 底层菜品列表
     *
     * 编辑情况下，展示底层菜品的信息，若底层菜品被删除则不展示
     * @param int $productMenuId
     * @return array
     */
    public static function productLists(int $productMenuId): array
    {
        $menuProducts = Product::getMenuProducts($productMenuId)->keyBy('id');

        // 当前菜单下的所有category
        $pIdCategorys = CategoryModel::query()
                                     ->where('menuId', $productMenuId)
                                     ->select('id', 'pid', 'name')
                                     ->get()
                                     ->keyBy('pid');

        return Product::getMenuProducts(0)->map(function ($item) use ($menuProducts, $pIdCategorys) {
            $menuItem = $menuProducts[$item['id']] ?? [];
            $isHot    = $isRecommend = $isSelected = 0;
            // 已勾选的内容
            if ($menuItem) {
                $isHot            = $menuItem['isHot'];
                $isRecommend      = $menuItem['isRecommend'];
                $isSelected       = 1;
                $menuItemCategory = $menuItem->categoryRel ?? '';
            } else {
                // 通过底层categoryId找到，当前菜单下的categoryId
                $menuItemCategory = $pIdCategorys[$item->categoryId] ?? [];
            }
            return [
                'id'          => $item['id'],
                'name'        => $menuItem['name'] ?? $item['name'],
                'category'    => [
                    'id'   => $menuItemCategory->id ?? 0,
                    'name' => $menuItemCategory->name ?? '',
                ],
                'price'       => $menuItem['price'] ?? $item['price'],
                'unit'        => $item['unit'],
                'isHot'       => $isHot,
                'isRecommend' => $isRecommend,
                'isSelected'  => $isSelected,
                'type'        => $item->type,
                'kind'        => $item->kind,
                'status'      => $item->status
            ];
        })->toArray();
    }

    /**
     * 各端 - 店铺下的菜品列表 - 只做筛选不做赋值
     * @param int $menudId
     * @param int $clientType
     * @return array
     * @throws ShopException
     */
    public static function shopProductLists(
        int $showPlatform,
        int $queryStatus = DBEnum::STATUS_ON
    ): array {
        $shopId  = (int)request()->header('shopId');
        $brandId = (int)request()->header('brandId');

        // 商品数据
        $ps        = new ProductShopService($brandId, $shopId);
        $listMerge = $ps->getShopProductList();

        return $ps->dealMapShopProductList($listMerge, $showPlatform, $queryStatus);
    }

    public static function listForCallingCards(int $menuId): array
    {
        $menu = ProductMenu::query()
                           ->where('id', $menuId)
                           ->first();
        if (null === $menu) {
            return [];
        }
        $data     = [];
        $products = Product::query()
                           ->with(['categoryRel'])
                           ->where('menuId', $menuId)
                           ->where('status', 0)
                           ->orderBy('sort', 'asc')
                           ->orderBy('id', 'asc')
                           ->get();
        foreach ($products as $product) {
            if (null === $product->categoryRel) {
                continue;
            }
            if (!isset($data[$product->categoryRel->name])) {
                $data[$product->categoryRel->name] = [
                    'name'    => $product->categoryRel->name,
                    'desc'    => $product->categoryRel->desc,
                    'sort'    => $product->categoryRel->sort,
                    'brandId' => $product->categoryRel->brandId,
                    'list'    => [],
                ];
            }
            $data[$product->categoryRel->name]['list'][] = [
                'id'       => $product->id,
                'name'     => $product->name,
                'desc'     => $product->desc,
                'imageUrl' => config('other.IMAGE_URL') . $product->imageUrl,
            ];
        }
        return array_values($data);
    }

    /**
     * @param object $params
     * @throws BaseException
     */
    public static function top(object $params)
    {
        try {
            if ($params->type) {
                //置顶
                ProductMenu::query()->where("id", $params->menuId)->update([
                    "isTop"   => 1,
                    "topTime" => time()
                ]);
            } else {
                //取消置顶
                ProductMenu::query()->where("id", $params->menuId)->update([
                    "isTop"   => 0,
                    "topTime" => 0
                ]);
            }
        } catch (\Exception $exception) {
            handleException($exception, "菜单置顶操作失败");
        }
    }


    /**
     * 单个菜单导出
     * @param int $productMenuId
     * @param int $type 默认0-脚本导出 1-接口请求导出
     */
    public static function menuExportById(int $productMenuId, int $type = 0)
    {
        $menuInfo = ProductMenu::query()->where('id', $productMenuId)->first();

        $menuProducts = Product::getMenuProducts($productMenuId)->keyBy('id');

        // 当前菜单下的所有category
        $pIdCategorys = CategoryModel::query()
                                     ->where('menuId', $productMenuId)
                                     ->select('id', 'pid', 'name')
                                     ->get()
                                     ->keyBy('id');

        $csvTitle = '菜品名称,菜品分类,销售价格,单位';

        $list = [];
        foreach ($menuProducts as $product) {
            $categoryName = $pIdCategorys[$product['categoryId']]['name'] ?? '';

            $list[] = $data = [
                $product['name'],
                $categoryName,
                bcdiv100($product['price']),
                $product['unit'],
            ];

            $csvTitle .= vsprintf("\n%s,%s,%s,%s", $data);
        }

        $filename = str_replace(['【', '】', '/'], [''], $menuInfo->name);
        if ($type) {// 接口请求导出
            self::exportList($list, $filename);
        } else {
            file_put_contents('./' . $filename . '.csv', $csvTitle);
        }

    }


    /**
     * 导出
     * @param array $list
     * @param string $name
     */
    public static function exportList(array $list, string $name)
    {
        ini_set('max_execution_time', 10000);
        header('Content-Disposition: attachment; filename=' . urlencode($name) . date('Y-m-d') . '.csv');

        // UTF8的BOM头
        $fd = fopen('php://output', 'w+');
        fwrite($fd, "\xEF\xBB\xBF");

        // 表头
        fputcsv(
            $fd, [
                '菜品名称',
                '菜品分类',
                '销售价格',
                '单位',
            ]
        );

        collect($list)->each(
            function ($item) use (&$fd) {
                fputcsv(
                    $fd, [
                        $item[0],
                        $item[1],
                        $item[2],
                        $item[3],
                    ]
                );
                ob_flush();
                flush();
            }
        );

        fputcsv($fd, []);

        if (is_resource($fd)) {
            fclose($fd);
        }
        die;
    }

}
